#include "Goblin.h"
#include "DestroyGameObjectMessage.h"
#include "CreateGoblinMessage.h"
#include "Game.h"
#include "AnimationSystem.h"
#include "GameplayState.h"
#include "Player.h"
#include "../SGD Wrappers/SGD_MessageManager.h"
#include "Projectile.h"
#include "../SGD Wrappers/SGD_AudioManager.h"

Goblin::Goblin()
{
	RegisterForEvent("ALERT_GOBLINS");
	StartAnimation("goblinwalking");
}

void Goblin::Update(float elapsedTime)
{
	pastPosition = m_ptPosition;

	Enemy::Update(elapsedTime);
	if (!updating) return;

	if (callTimer > 0.0f)
	{
		callTimer -= elapsedTime;

		if (callTimer <= 0.0f) StartAnimation("goblinwalking");
	}
}

/*virtual*/ bool Goblin::DoAttack()
{
	GameplayState *gameplay = GameplayState::GetInstance();
	float distanceFromPlayer = (gameplay->GetPlayer()->GetPosition() - m_ptPosition).ComputeLength();
	float playerToEdgeOfScreen = Game::GetInstance()->GetCameraPos().x + Game::GetInstance()->GetScreenWidth() - gameplay->GetPlayer()->GetPosition().x;

	if (angry)
		return (distanceFromPlayer < playerToEdgeOfScreen + 100);
	else
		return (distanceFromPlayer < Game::GetInstance()->GetScreenWidth() / 3);
}

/*virtual*/ void Goblin::Attack()
{
	GameplayState *gameplay = GameplayState::GetInstance();
	float distanceFromPlayer = (gameplay->GetPlayer()->GetPosition() - m_ptPosition).ComputeLength();

	//If a small distance from player then call in help
	if (callTimer > 0.0f)
	{
		m_vtVelocity = { 0.0f, 0.0f };
	}
	else if (state == State::CLOSEIN)
	{
		if (canSpawnFriends && distanceFromPlayer > 150.0f)
		{
			callTimer = 1.0f;
			StartAnimation("goblinalert");
		}
		else
		{
			if (distanceFromPlayer > 20.0f)
			{
				if (gameplay->GetPlayer()->GetPosition().x < m_ptPosition.x)
					MoveLeft();
				else
					MoveRight();
			}
			else
			{
				m_vtVelocity.x = 0.0f;
				state = State::ATTACK;
			}
		}
	}
}

/*virtual*/ void Goblin::EnterIdle()
{
	if (state == State::IDLE) return;
	Enemy::EnterIdle();

	StartAnimation("goblingidle");
}

/*virtual*/ void Goblin::EnterPatrol()
{
	if (state == State::PATROL) return;
	Enemy::EnterPatrol();

	StartAnimation("goblinwalking");
}

/*virtual*/ void Goblin::EnterJumping()
{
	if (state == State::JUMPING) return;
	Enemy::EnterJumping();

	StartAnimation("goblinwalking");
}

/*virtual*/ void Goblin::EnterCloseIn()
{
	if (state == State::CLOSEIN) return;
	Enemy::EnterCloseIn();

	StartAnimation("goblinwalking");
}

/*virtual*/ void Goblin::EnterAttack()
{
	if (state == State::ATTACK) return;
	Enemy::EnterAttack();

	StartAnimation("goblinwalking");
}

/*virtual*/ void Goblin::EnterDead()
{
	if (state == State::DEAD) return;
	Enemy::EnterDead();

	StartAnimation("goblinwalking");
}

/*virtual*/ void Goblin::HandleEvent(const SGD::Event* pEvent) /*override*/
{
	if (canSpawnFriends && !hit && pEvent->GetEventID() == "ALERT_GOBLINS" && animInfo.GetCurrAnimation() == "goblinalert")
	{
		//spawn some goblin friends
		float edgeOfScreen = Game::GetInstance()->GetCameraPos().x + Game::GetInstance()->GetScreenWidth();

		int spawnNum = rand() % 3 + 1;
		for (int i = 0; i < spawnNum; i++)
		{
			SGD::MessageManager::GetInstance()->QueueMessage(
				new CreateGoblinMessage(edgeOfScreen + (rand() % 60), m_ptPosition.y, false, true)
				);
		}

		canSpawnFriends = false;
	}
	else
		MovingObject::HandleEvent(pEvent);
}

void Goblin::HandleCollision(GameObject* pOther)
{
	if (pOther->GetType() == MovingObject::OBJ_BULLET)
	{
		// don't shoot yourself
		if (((Projectile *)pOther)->GetOwner() == this) return;

		// call MovingObjects HandleCollision
		MovingObject::HandleCollision(pOther);
		// set hit for spawning ability
		hit = true;
		// play hit sfx
		SGD::AudioManager::GetInstance()->PlayAudio(damageAudio);
	}

	// dont call this if it is NOT the player (conflicts with the overlap code)
	if (pOther == GameplayState::GetInstance()->GetPlayer())
		CharacterCollision(pOther);

	// unique to goblins, keeps 'support' troops from stacking
	MovingObject* tempEnemy = dynamic_cast<MovingObject*>(pOther);
	if (tempEnemy && tempEnemy->GetType() == MovingObject::OBJ_ENEMY)
	{
		if (GetRect().IsIntersecting(tempEnemy->GetRect()))
		{
			if (GetRect().right > tempEnemy->GetRect().left && GetRect().left < tempEnemy->GetRect().left)
			{
				if (GetVelocity().x > 0 && tempEnemy->GetVelocity().x > 0)
					m_ptPosition = pastPosition;

				if (GetVelocity().x < 0 && tempEnemy->GetVelocity().x < 0)
					tempEnemy->SetPosition(tempEnemy->GetPastPosition());
			}
			if (GetRect().left < tempEnemy->GetRect().right && GetRect().right > tempEnemy->GetRect().right)
			{
				if (GetVelocity().x > 0 && tempEnemy->GetVelocity().x > 0)
					tempEnemy->SetPosition(tempEnemy->GetPastPosition());

				if (GetVelocity().x < 0 && tempEnemy->GetVelocity().x < 0)
					m_ptPosition = pastPosition;
			}
		}
	}
}
